gl renderer: Fix opacity nodes with overlapping child nodes
authorTimm Bäder <mail@baedert.org>
Sat, 13 Jul 2019 15:35:59 +0000 (17:35 +0200)
committerTimm Bäder <mail@baedert.org>
Sun, 14 Jul 2019 08:08:04 +0000 (10:08 +0200)
gsk/gl/gskglrenderer.c
testsuite/gsk/compare/opacity-overlapping-children.node [new file with mode: 0644]
testsuite/gsk/compare/opacity-overlapping-children.png [new file with mode: 0644]
testsuite/gsk/meson.build

index 46c9e64c1ce441a702d928f9eba418934a7fbe2d..65fdc0c13e305794b8bcaa06637267b219ef91b2 100644 (file)
@@ -1015,12 +1015,49 @@ render_opacity_node (GskGLRenderer   *self,
                      GskRenderNode   *node,
                      RenderOpBuilder *builder)
 {
+  GskRenderNode *child = gsk_opacity_node_get_child (node);
+  const float opacity = gsk_opacity_node_get_opacity (node);
   float prev_opacity;
 
-  prev_opacity = ops_set_opacity (builder,
-                                  builder->current_opacity * gsk_opacity_node_get_opacity (node));
+  if (gsk_render_node_get_node_type (child) == GSK_CONTAINER_NODE)
+    {
+      const float min_x = builder->dx + node->bounds.origin.x;
+      const float min_y = builder->dy + node->bounds.origin.y;
+      const float max_x = min_x + node->bounds.size.width;
+      const float max_y = min_y + node->bounds.size.height;
+      gboolean is_offscreen;
+      TextureRegion region;
+
+      /* The semantics of an opacity node mandate that when, e.g., two color nodes overlap,
+       * there may not be any blending between them */
+      add_offscreen_ops (self, builder, &child->bounds,
+                         child,
+                         &region, &is_offscreen,
+                         FORCE_OFFSCREEN | RESET_OPACITY | RESET_CLIP);
 
-  gsk_gl_renderer_add_render_ops (self, gsk_opacity_node_get_child (node), builder);
+      prev_opacity = ops_set_opacity (builder,
+                                      builder->current_opacity * opacity);
+
+      ops_set_program (builder, &self->blit_program);
+      ops_set_texture (builder, region.texture_id);
+
+      ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+        { { min_x, min_y }, { region.x,  region.y2 }, },
+        { { min_x, max_y }, { region.x,  region.y  }, },
+        { { max_x, min_y }, { region.x2, region.y2 }, },
+
+        { { max_x, max_y }, { region.x2, region.y  }, },
+        { { min_x, max_y }, { region.x,  region.y  }, },
+        { { max_x, min_y }, { region.x2, region.y2 }, },
+      });
+    }
+  else
+    {
+      prev_opacity = ops_set_opacity (builder,
+                                      builder->current_opacity * opacity);
+
+      gsk_gl_renderer_add_render_ops (self, child, builder);
+    }
 
   ops_set_opacity (builder, prev_opacity);
 }
@@ -1290,7 +1327,7 @@ render_rounded_clip_node (GskGLRenderer       *self,
         { { min_x, min_y }, { 0, 1 }, },
         { { min_x, max_y }, { 0, 0 }, },
         { { max_x, min_y }, { 1, 1 }, },
+
         { { max_x, max_y }, { 1, 0 }, },
         { { min_x, max_y }, { 0, 0 }, },
         { { max_x, min_y }, { 1, 1 }, },
diff --git a/testsuite/gsk/compare/opacity-overlapping-children.node b/testsuite/gsk/compare/opacity-overlapping-children.node
new file mode 100644 (file)
index 0000000..0267b59
--- /dev/null
@@ -0,0 +1,13 @@
+opacity {
+  opacity: 0.4;
+  child: container {
+     color {
+       color: blue;
+       bounds: 0 0 100 100;
+     }
+     color {
+       color: red;
+       bounds: 50 50 100 100;
+     }
+  }
+}
\ No newline at end of file
diff --git a/testsuite/gsk/compare/opacity-overlapping-children.png b/testsuite/gsk/compare/opacity-overlapping-children.png
new file mode 100644 (file)
index 0000000..ef67840
Binary files /dev/null and b/testsuite/gsk/compare/opacity-overlapping-children.png differ
index 2208c1a6d6215adf9af0220b668ff2b027d90b71..574f9368ca946681a1f6aeb58f4099e6448f5d8a 100644 (file)
@@ -58,7 +58,8 @@ compare_render_tests = [
   'texture-url',
   'color-matrix-identity',
   'clip-nested1',
-  'scale-up-down'
+  'scale-up-down',
+  'opacity-overlapping-children',
 ]
 
 renderers = [